package com.vhly.classfile;

import com.vhly.classfile.util.CPTool;

import java.io.*;
import java.util.Enumeration;
import java.util.Vector;

/**
 * Java Class File
 */
public class JavaClass {
    /**
     * magic must 0xCAFEBABE
     */
    private int magic;
    private int min_ver;
    private int maj_ver;
    /**
     * CP Count
     */
    private int cp_count;
    /**
     * 常数池
     */
    private ConstantPool cp;
    /**
     * 访问权限
     */
    private int access;
    private int this_index;
    private int super_index;
    //    private int interface_count;
    private Vector<CPClass> interfaces;
    private int field_count;
    private Vector fds;
    private int method_count;
    private Vector mds;
    private int attribute_count;
    private Vector<Attribute> atts;
    /**
     * SourcFile
     */
    private String source;
    private String self;
    private int source_index;
    private int inner_index;
    private boolean bNeedPop;
    private int pix;

    public JavaClass() {
        magic = 0xcafebabe;
        min_ver = 0;
        maj_ver = 0;
        cp_count = 0;
        cp = new ConstantPool();
        cp.addCPEntry(new NullCPEntry());
        access = 1;
        this_index = 0;
        super_index = 0;
//        interface_count = 0;
        interfaces = new Vector<CPClass>();
        field_count = 0;
        fds = new Vector();
        method_count = 0;
        mds = new Vector();
        attribute_count = 0;
        atts = new Vector<Attribute>();
        source_index = -1;
        inner_index = -1;
        bNeedPop = false;
    }

    /**
     * 删除指定索引处的常数项
     *
     * @param i
     */
    public void delCPEntryAt(int i) {
        relocateField(i, false);
        relocateMethod(i, false);
        relocateAttribute(i, false);
        if (this_index >= i)
            this_index--;
        if (super_index >= i)
            super_index--;
    }

    public void addCPEntryAt(int i) {
        relocateField(i, true);
        relocateMethod(i, true);
        relocateAttribute(i, true);
        if (this_index >= i)
            this_index++;
        if (super_index >= i)
            super_index++;
    }

    private void relocateField(int i, boolean flag) {
        for (int j = 0; j < fds.size(); j++) {
            Field field = (Field) (Field) fds.elementAt(j);
            int k = field.getNameIndex();
            int l = field.getSigIndex();
            int i1 = -1;
            int j1 = -1;
            boolean flag1 = false;
            for (int l1 = 0; l1 < field.getAttributeCount(); l1++) {
                Attribute attribute = field.getAttribute(l1);
                int k1 = attribute.getNameIndex();
                CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(k1);
                String s = cputf8.getString();
                s = s.trim();
                if (s.equals("ConstantValue")) {
                    i1 = k1;
                    ConstantValue constantvalue1 = (ConstantValue) attribute;
                    j1 = constantvalue1.getValueIndex();
                }
            }

            if (flag) {
                if (k >= i)
                    k++;
                if (l >= i)
                    l++;
                if (i1 != -1) {
                    if (i1 >= i)
                        i1++;
                    if (j1 >= i)
                        j1++;
                }
            } else {
                if (k > i)
                    k--;
                if (l > i)
                    l--;
                if (i1 != -1) {
                    if (i1 > i)
                        i1--;
                    if (j1 > i)
                        j1--;
                }
            }
            field.setNameIndex(k);
            field.setSigIndex(l);
            for (int i2 = 0; i2 < field.getAttributeCount(); i2++) {
                Attribute attribute1 = field.getAttribute(i2);
                if (attribute1 instanceof ConstantValue) {
                    ConstantValue constantvalue = (ConstantValue) attribute1;
                    constantvalue.setNameIndex(i1);
                    constantvalue.setValueIndex(j1);
                }
            }

        }

    }

    private void relocateMethod(int i, boolean flag) {
        for (int j = 0; j < mds.size(); j++) {
            Method method = (Method) (Method) mds.elementAt(j);
            int k = method.getNameIndex();
            int l = method.getSigIndex();
            int i1 = method.getCodeNameIndex();
            int j1 = method.getExceptionNameIndex();
            int k1 = method.getDapercatedNameIndex();
            if (flag) {
                if (k >= i)
                    k++;
                if (l >= i)
                    l++;
                if (i1 >= i)
                    i1++;
                if (j1 >= i)
                    j1++;
                if (k1 >= i)
                    k1++;
            } else {
                if (k > i)
                    k--;
                if (l > i)
                    l--;
                if (i1 > i)
                    i1--;
                if (j1 > i)
                    j1--;
                if (k1 > i)
                    k1--;
            }
            method.setNameIndex(k);
            method.setSigIndex(l);
            method.setCodeNameIndex(i1);
            method.setExceptionNameIndex(j1);
            method.setDapercatedNameIndex(k1);
        }

    }

    private void relocateAttribute(int i, boolean flag) {
        if (!flag) ;
    }

    public void addField(Field field) {
        fds.add(field);
        field_count++;
    }

    public void addMethod(Method method) {
        mds.add(method);
        method_count++;
    }

    public int getFieldCount() {
        field_count = fds.size();
        return field_count;
    }

    public int getInterfaceCount() {
        return interfaces.size();
    }

    public CPClass[] getInterfacesClasses() {
        int size = interfaces.size();
        CPClass[] ret = null;
        if (size > 0) {
            ret = new CPClass[size];
            interfaces.copyInto(ret);
        }
        return ret;
    }

    public String[] getInterfacesName() {
        int interface_count = interfaces.size();
        if (interface_count == 0)
            return null;
        String as[] = new String[interface_count];
        for (int i = 0; i < interface_count; i++) {
            CPClass cpclass = interfaces.elementAt(i);
            int j = cpclass.getNameIndex();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(j);
            as[i] = cputf8.getString();
        }

        return as;
    }

    public int addInterfaceClass(String className) {
        int index = CPTool.addClass(cp, className);
        if (index > 0) {
            CPEntry cpe = cp.getCPEntryAtIndex(index);
            if (cpe instanceof CPClass) {
                CPClass cpc = (CPClass) cpe;
                if (!interfaces.contains(cpc)) {
                    interfaces.add(cpc);
                }
            }
        }
        return index;
    }

    public int getInnerIndex() {
        return inner_index;
    }

    public void setInnerIndex(int i) {
        inner_index = i;
    }

    public InnerClasses getInnerClasses() {
        return (InnerClasses) atts.elementAt(inner_index);
    }

    public void setInnerClasses(InnerClasses innerclasses) {
        if (inner_index == -1) {
            atts.add(innerclasses);
            inner_index = atts.size() - 1;
        } else {
            atts.setElementAt(innerclasses, inner_index);
        }
    }

    public int getMinVersion() {
        return min_ver;
    }

    public void setMinVersion(int i) {
        min_ver = i;
    }

    public int getMajVersion() {
        return maj_ver;
    }

    public void setMajVersion(int i) {
        maj_ver = i;
    }

    public int getCPCount() {
        return cp_count;
    }

    public void setCPCount(int i) {
        cp_count = i;
    }

    public ConstantPool getCP() {
        return cp;
    }

    public int getAccess() {
        return access;
    }

    public void setAccess(int i) {
        access = i;
    }

    public int getThisIndex() {
        return this_index;
    }

    public String getThisName() {
        CPClass cpclass = (CPClass) cp.getCPEntryAtIndex(this_index);
        int i = cpclass.getNameIndex();
        CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
        self = cputf8.getString();
        return cputf8.getString();
    }

    public void setThisIndex(int i) {
        this_index = i;
    }

    public void setThisName(String s) {
        if (this_index == 0) {
            this_index = CPTool.addClass(cp, s);
        } else {
            CPClass cpclass = (CPClass) cp.getCPEntryAtIndex(this_index);
            int i = cpclass.getNameIndex();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
            cputf8.setString(s);
            if (inner_index != -1) {
                InnerClasses innerclasses = (InnerClasses) atts.elementAt(inner_index);
                Enumeration enumeration = innerclasses.getInnerClasses();
                do {
                    if (!enumeration.hasMoreElements())
                        break;
                    InnerClass innerclass = (InnerClass) enumeration.nextElement();
                    int j = innerclass.getIC();
                    CPClass cpclass1 = (CPClass) cp.getCPEntryAtIndex(j);
                    int k = cpclass1.getNameIndex();
                    CPUtf8 cputf8_1 = (CPUtf8) cp.getCPEntryAtIndex(k);
                    String s1 = cputf8_1.getString();
                    int l = s1.indexOf(self);
                    if (l != -1) {
                        int i1 = s1.lastIndexOf("$");
                        String s2 = s1.substring(i1);
                        String s3 = (new StringBuilder()).append(s).append("$").append(s2).toString();
                        cputf8_1.setString(s3);
                    }
                } while (true);
            }
        }
        self = s;
    }

    public int getSuperIndex() {
        return super_index;
    }

    public void setSuperIndex(int i) {
        super_index = i;
    }

    public String getSuperName() {
        CPClass cpclass = (CPClass) cp.getCPEntryAtIndex(super_index);
        int i = cpclass.getNameIndex();
        CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
        return cputf8.getString();
    }

    public void setSuperName(String s) {
        if (super_index == 0) {
            super_index = CPTool.addClass(cp, s);
        } else {
            CPClass cpclass = (CPClass) cp.getCPEntryAtIndex(super_index);
            int i = cpclass.getNameIndex();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
            cputf8.setString(s);
        }
    }

    public Enumeration getFields() {
        return fds.elements();
    }

    public Field getField(int i) {
        if (i >= fds.size())
            return null;
        else
            return (Field) fds.elementAt(i);
    }

    public Field getField(String s) {
        for (Enumeration enumeration = getFields(); enumeration.hasMoreElements();) {
            Field field = (Field) enumeration.nextElement();
            int i = field.getNameIndex();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
            String s1 = cputf8.getString().trim();
            System.out.println((new StringBuilder()).append("Find the Field name is:").append(s1).toString());
            if (s1.equals(s))
                return field;
        }

        return null;
    }

    public Enumeration getMethods() {
        return mds.elements();
    }

    public Method getMethod(int i) {
        if (i >= mds.size())
            return null;
        else
            return (Method) mds.elementAt(i);
    }

    public Method getMethod(String s) {
        Object obj = null;
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Find The ").append(s).append(" Method").toString());
        for (Enumeration enumeration = getMethods(); enumeration.hasMoreElements();) {
            Method method = (Method) enumeration.nextElement();
            int i = method.getNameIndex();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(i);
            String s1 = cputf8.getString();
            s1 = s1.trim();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("Find The ").append(s1).append(" Method").toString());
            if (s1.equals(s)) {
                if (Debug.isEnabled())
                    System.out.println((new StringBuilder()).append("Found the method:").append(s).toString());
                return method;
            }
        }

        return null;
    }

    public int addAttribute(Attribute attr) {
        int ret = -1;
        if (attr != null) {
            atts.add(attr);
            ret = atts.size() - 1;
        }
        return ret;
    }

    public int getSourceIndex() {
        return source_index;
    }

    public void setSourceIndex(int i) {
        source_index = i;
    }

    public int getSourceFileIndex() {
        SourceFile sourcefile = getSourceFile();
        if (sourcefile != null) {
            int i = sourcefile.getSourceIndex();
            return i;
        } else {
            return -1;
        }
    }

    public void setSourceFileIndex(int i) {
        SourceFile sourcefile = getSourceFile();
        if (sourcefile == null) {
            return;
        } else {
            sourcefile.setSourceIndex(i);
            return;
        }
    }

    public Enumeration getAttributes() {
        return atts.elements();
    }

    public SourceFile getSourceFile() {
        if (source_index == -1) {
            return null;
        } else {
            SourceFile sourcefile = (SourceFile) atts.elementAt(source_index);
            return sourcefile;
        }
    }

    public String getSourceFileName() {
        int i = getSourceFileIndex();
        if (i == -1) {
            return null;
        } else {
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(getSourceFileIndex());
            return cputf8.getString();
        }
    }

    public void setSourceFileName(String s) {
        String s1 = s;
        if (s == null)
            s1 = "vhly[FR]";
        else if (s.length() < 1)
            s1 = "vhly[FR]";
        SourceFile sourcefile = getSourceFile();
        if (sourcefile == null) {
            return;
        } else {
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(sourcefile.getSourceIndex());
            cputf8.setString(s1);
            return;
        }
    }

    public void read(InputStream inputstream) {
        try {
            if (Debug.isEnabled())
                System.out.println("JavaClass obj Start Read a ClassFile from a InputStream");
            DataInputStream datainputstream = null;
            BufferedInputStream bufferedinputstream = new BufferedInputStream(inputstream);
            datainputstream = new DataInputStream(bufferedinputstream);
            magic = datainputstream.readInt();
            if (Debug.isEnabled())
                System.out.println("JavaClass Read ClassFile Magic code if is not 0xCAFEBABE then throw a RuntimeException");
            if (magic != 0xcafebabe)
                throw new RuntimeException("This File is Not a Class File or File Format is Wrong");
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Magic is ").append(magic).toString());
            min_ver = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Min Version:").append(min_ver).toString());
            maj_ver = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Maj Version:").append(maj_ver).toString());
            cp_count = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read CP Count:").append(cp_count).toString());
            readCP(datainputstream);
            if (Debug.isEnabled())
                System.out.println("JavaClass Read CP: Finished");
            if (!bNeedPop)
                access = datainputstream.readUnsignedShort();
            else
                access = datainputstream.read();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read access:").append(access).append("\n\t\tAccess Name:").append(AccessFlag.toString(access)).toString());
            this_index = datainputstream.readUnsignedShort();
            if (Debug.isEnabled()) {
                System.out.println((new StringBuilder()).append("JavaClass Read this:").append(this_index).toString());
                System.out.println((new StringBuilder()).append("\t\tThis Class Name:").append(getThisName()).toString());
            }
            self = getThisName();
            super_index = datainputstream.readUnsignedShort();
            if (Debug.isEnabled()) {
                System.out.println((new StringBuilder()).append("JavaClass Read super:").append(super_index).toString());
                System.out.println((new StringBuilder()).append("\t\tThis Class Super Name:").append(getSuperName()).toString());
            }
            int interface_count = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Interface_count:").append(interface_count).toString());
            if (interface_count != 0) {
                if (Debug.isEnabled())
                    System.out.println("\t\tInterface_count is not 0 so start Read Interface");
                interfaces = new Vector<CPClass>();
                int cindex;
                for (int i = 0; i < interface_count; i++) {
                    cindex = datainputstream.readUnsignedShort();
                    CPEntry cpentry = cp.getCPEntryAtIndex(cindex);
                    if (cpentry instanceof CPClass) {
                        interfaces.add((CPClass) cpentry);
                        if (Debug.isEnabled()) {
                            System.out.println((new StringBuilder()).append("JavaClass Read Interface[").append(i).append("]:").append(cindex).toString());
                            System.out.println((new StringBuilder()).append("\t Interface Type is ").append(cpentry.getType()).toString());
                        }
                    }

                }

            }
            field_count = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Field_count:").append(field_count).toString());
            if (field_count != 0) {
                if (Debug.isEnabled())
                    System.out.println("JavaClass Read Field_count is not 0 so start Read");
                fds = new Vector();
                readField(datainputstream);
                if (Debug.isEnabled())
                    System.out.println("ReadField Finished");
            }
            method_count = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read Method_count:").append(method_count).toString());
            if (method_count != 0) {
                mds = new Vector();
                readMethod(datainputstream);
                if (Debug.isEnabled())
                    System.out.println("Read Method is Finished");
            }
            attribute_count = datainputstream.readUnsignedShort();
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read attriubte_count:").append(attribute_count).toString());
            if (attribute_count != 0) {
                readAttribute(datainputstream);
                if (Debug.isEnabled())
                    System.out.println("Attribute Finished");
            }
            datainputstream.close();
            bufferedinputstream.close();
        }
        catch (IOException ioexception) {
            ioexception.printStackTrace();
            throw new RuntimeException(ioexception.getMessage());
        }
    }

    private void readCP(DataInputStream datainputstream)
            throws IOException {
        if (cp.size() > 1) {
            cp.removeAllElements();
            NullCPEntry nullcpentry = new NullCPEntry();
            cp.addCPEntry(nullcpentry);
        }
        for (int i = 1; i < cp_count; i++) {
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("JavaClass Read CP[").append(i).append("]:").toString());
            int j = datainputstream.readUnsignedByte();
            if (Debug.isEnabled())
                System.out.print((new StringBuilder()).append("\t\tType is ").append(j).append(" String Type:").toString());
            switch (j) {
                default:
                    System.out.println((new StringBuilder()).append("Error Tag is ").append(j).toString());
                    throw new RuntimeException((new StringBuilder()).append("Error Tag is Wrong :").append(j).toString());

                case 1: // '\001'
                    if (Debug.isEnabled())
                        System.out.print("CPUtf8!");
                    CPUtf8 cputf8 = new CPUtf8();
                    cputf8.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" String is: ").append(cputf8.getString()).toString());
                    cp.addCPEntry(cputf8);
                    break;

                case 2: // '\002'
                    if (Debug.isEnabled())
                        System.out.println("CPUnicode!");
                    CPUnicode cpunicode = new CPUnicode();
                    cpunicode.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" String is: ").append(cpunicode.getString()).toString());
                    cp.addCPEntry(cpunicode);
                    break;

                case 3: // '\003'
                    if (Debug.isEnabled())
                        System.out.println("CPInteger!");
                    CPInteger cpinteger = new CPInteger();
                    cpinteger.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Value is: ").append(cpinteger.getInt()).toString());
                    cp.addCPEntry(cpinteger);
                    break;

                case 4: // '\004'
                    if (Debug.isEnabled())
                        System.out.println("CPFloat!");
                    CPFloat cpfloat = new CPFloat();
                    cpfloat.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Value is: ").append(cpfloat.getFloat()).toString());
                    cp.addCPEntry(cpfloat);
                    break;

                case 5: // '\005'
                    if (Debug.isEnabled())
                        System.out.println("CPLong!");
                    CPLong cplong = new CPLong();
                    cplong.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Value is: ").append(cplong.getLong()).toString());
                    cp.addCPEntry(cplong);
                    NullCPEntry nullcpentry1 = new NullCPEntry();
                    cp.addCPEntry(nullcpentry1);
                    i++;
                    break;

                case 6: // '\006'
                    if (Debug.isEnabled())
                        System.out.println("CPDouble!");
                    CPDouble cpdouble = new CPDouble();
                    cpdouble.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Value is: ").append(cpdouble.getDouble()).toString());
                    cp.addCPEntry(cpdouble);
                    NullCPEntry nullcpentry2 = new NullCPEntry();
                    cp.addCPEntry(nullcpentry2);
                    i++;
                    break;

                case 7: // '\007'
                    if (Debug.isEnabled())
                        System.out.println("CPClass!");
                    CPClass cpclass = new CPClass();
                    cpclass.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Name Index is: ").append(cpclass.getNameIndex()).toString());
                    cp.addCPEntry(cpclass);
                    break;

                case 8: // '\b'
                    if (Debug.isEnabled())
                        System.out.println("CPString!");
                    CPString cpstring = new CPString();
                    cpstring.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" String Index is: ").append(cpstring.getStringIndex()).toString());
                    cp.addCPEntry(cpstring);
                    break;

                case 9: // '\t'
                    if (Debug.isEnabled())
                        System.out.println("CPField!");
                    CPField cpfield = new CPField();
                    cpfield.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Class Index is: ").append(cpfield.getClassIndex()).append("   NameAndType is: ").append(cpfield.getSigIndex()).toString());
                    cp.addCPEntry(cpfield);
                    break;

                case 10: // '\n'
                    if (Debug.isEnabled())
                        System.out.println("CPMethod!");
                    CPMethod cpmethod = new CPMethod();
                    cpmethod.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Class Index is: ").append(cpmethod.getClassIndex()).append("   NameAndType is: ").append(cpmethod.getSigIndex()).toString());
                    cp.addCPEntry(cpmethod);
                    break;

                case 11: // '\013'
                    if (Debug.isEnabled())
                        System.out.println("CPInterfaceMethod!");
                    CPInterfaceMethod cpinterfacemethod = new CPInterfaceMethod();
                    cpinterfacemethod.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Class Index is: ").append(cpinterfacemethod.getClassIndex()).append("   NameAndType is: ").append(cpinterfacemethod.getSigIndex()).toString());
                    cp.addCPEntry(cpinterfacemethod);
                    break;

                case 12: // '\f'
                    if (Debug.isEnabled())
                        System.out.println("CPNameAndType!");
                    CPNameAndType cpnameandtype = new CPNameAndType();
                    cpnameandtype.read(datainputstream);
                    if (Debug.isEnabled())
                        System.out.println((new StringBuilder()).append(" Name Index is: ").append(cpnameandtype.getNameIndex()).append("   Type index is: ").append(cpnameandtype.getSigIndex()).toString());
                    cp.addCPEntry(cpnameandtype);
                    break;
            }
        }

    }

    private void readField(DataInputStream datainputstream)
            throws IOException {
        if (fds.size() > 1)
            fds.removeAllElements();
        if (field_count == 0)
            return;
        if (Debug.isEnabled())
            System.out.println("JavaClass Start Read Field");
        for (int i = 0; i < field_count; i++) {
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("Field[").append(i).append("]:").toString());
            Field field = new Field(cp);
            field.read(datainputstream);
            if (Debug.isEnabled()) {
                System.out.print("\tField Name:");
                CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(field.getNameIndex());
                System.out.print((new StringBuilder()).append(" ").append(cputf8.getString()).toString());
                System.out.print(" Sig/Type:");
                cputf8 = (CPUtf8) cp.getCPEntryAtIndex(field.getSigIndex());
                Signature signature = new Signature(cputf8.getString());
                System.out.println((new StringBuilder()).append(" ").append(cputf8.getString()).append(" Java String ").append(signature.getFieldType()).toString());
                Enumeration enumeration1 = field.getAttributes();
                signature = null;
                CPUtf8 cputf8_1;
                for (; enumeration1.hasMoreElements(); System.out.println((new StringBuilder()).append("Field 's Attribute: ").append(cputf8_1.getString()).toString())) {
                    Attribute attribute1 = (Attribute) enumeration1.nextElement();
                    cputf8_1 = (CPUtf8) cp.getCPEntryAtIndex(attribute1.getNameIndex());
                }

            }
            Enumeration enumeration = field.getAttributes();
            int j = 0;
            do {
                if (!enumeration.hasMoreElements())
                    break;
                Attribute attribute = (Attribute) enumeration.nextElement();
                int k = attribute.getNameIndex();
                CPUtf8 cputf8_2 = (CPUtf8) cp.getCPEntryAtIndex(k);
                String s = cputf8_2.getString();
                if (s.equals("ConstantValue")) {
                    field.setCVIndex(j);
                    break;
                }
                j++;
            } while (true);
            fds.add(field);
        }

    }

    private void readMethod(DataInputStream datainputstream)
            throws IOException {
        if (mds.size() > 1)
            mds.removeAllElements();
        if (method_count == 0)
            return;
        if (Debug.isEnabled())
            System.out.println("JavaClass Start Read Method");
        for (int i = 0; i < method_count; i++) {
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("\tMethod[").append(i).append("]:").toString());
            Method method = new Method(cp);
            method.read(datainputstream);
            if (Debug.isEnabled()) {
                System.out.print("\t\tMethod Name:");
                CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(method.getNameIndex());
                System.out.print((new StringBuilder()).append(" ").append(cputf8.getString()).toString());
                System.out.print(" Sig/Type:");
                cputf8 = (CPUtf8) cp.getCPEntryAtIndex(method.getSigIndex());
                Signature signature = new Signature(cputf8.getString());
                System.out.println((new StringBuilder()).append(" ").append(cputf8.getString()).append(" Java String ").append(signature.getReturnType()).append(signature.getParameters()).toString());
                signature = null;
                CPUtf8 cputf8_1;
                for (Enumeration enumeration1 = method.getAttributes(); enumeration1.hasMoreElements(); System.out.println((new StringBuilder()).append("Method 's Attribute: ").append(cputf8_1.getString()).toString())) {
                    Attribute attribute1 = (Attribute) enumeration1.nextElement();
                    cputf8_1 = (CPUtf8) cp.getCPEntryAtIndex(attribute1.getNameIndex());
                }

            }
            Enumeration enumeration = method.getAttributes();
            for (int j = 0; enumeration.hasMoreElements(); j++) {
                Attribute attribute = (Attribute) enumeration.nextElement();
                CPUtf8 cputf8_2 = (CPUtf8) cp.getCPEntryAtIndex(attribute.getNameIndex());
                String s = cputf8_2.getString();
                if (s.equals("Code")) {
                    method.setCodeIndex(j);
                    continue;
                }
                if (s.equals("Excepations"))
                    method.setExceptionIndex(j);
            }

            mds.add(method);
        }

    }

    private void readAttribute(DataInputStream datainputstream)
            throws IOException {
        if (attribute_count == 0)
            return;
        if (Debug.isEnabled())
            System.out.println("JavaClass Start Read Attribute");
        for (int i = 0; i < attribute_count; i++) {
            int j = datainputstream.readUnsignedShort();
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(j);
            String s = cputf8.getString().trim();
            if (s.equals("SourceFile")) {
                if (Debug.isEnable())
                    System.out.println("   Find a SourceFile Attribute");
                SourceFile sourcefile = new SourceFile();
                sourcefile.setNameIndex(j);
                sourcefile.setDataLen(datainputstream.readInt());
                sourcefile.setSourceIndex(datainputstream.readUnsignedShort());
                atts.add(sourcefile);
                source_index = i;
                continue;
            }
            if (s.equals("InnerClasses")) {
                if (Debug.isEnable())
                    System.out.println("   Find a InnerClasses Attribute");
                InnerClasses innerclasses = new InnerClasses();
                innerclasses.setNameIndex(j);
                innerclasses.read(datainputstream, false);
                atts.add(innerclasses);
                inner_index = i;
                continue;
            }
            if (Debug.isEnable())
                System.out.println("   Find a Unknown Attribute");
            Unknown unknown = new Unknown();
            unknown.setNameIndex(j);
            unknown.read(datainputstream, false);
            atts.add(unknown);
        }

    }

    private void writeCP(DataOutputStream dataoutputstream)
            throws IOException {
        if (Debug.isEnabled())
            System.out.println("JavaClass Start Write CP");
        for (int i = 1; i < cp.size(); i++) {
            CPEntry cpentry = cp.getCPEntryAtIndex(i);
            if (Debug.isEnabled()) {
                System.out.print((new StringBuilder()).append("  CP[").append(i).append("]").toString());
                System.out.print("    Write a CPEntry  type is ");
                switch (cpentry.getType()) {
                    case 1: // '\001'
                        System.out.println(" CPUtf8");
                        break;

                    case 2: // '\002'
                        System.out.println("CPUnicode");
                        break;

                    case 3: // '\003'
                        System.out.println("CPInteger");
                        break;

                    case 4: // '\004'
                        System.out.println("CPFloat");
                        break;

                    case 5: // '\005'
                        System.out.println("CPLong");
                        break;

                    case 6: // '\006'
                        System.out.println("CPDouble");
                        break;

                    case 7: // '\007'
                        System.out.println("CPClass");
                        break;

                    case 8: // '\b'
                        System.out.println("CPString");
                        break;

                    case 9: // '\t'
                        System.out.println("CPField");
                        break;

                    case 10: // '\n'
                        System.out.println("CPMethod");
                        break;

                    case 11: // '\013'
                        System.out.println("CPInterfaceMethod");
                        break;

                    case 12: // '\f'
                        System.out.println("CPNameAndType");
                        break;

                    default:
                        System.out.println("CPNull");
                        break;
                }
            }
            cpentry.write(dataoutputstream);
        }

    }

    public void write(DataOutputStream dataoutputstream)
            throws IOException {
        dataoutputstream.writeInt(0xcafebabe);
        if (Debug.isEnabled())
            System.out.println("Write Magic code 0xCAFEBABE");
        dataoutputstream.writeShort(min_ver);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write Min Version ").append(min_ver).toString());
        dataoutputstream.writeShort(maj_ver);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write Maj Version ").append(maj_ver).toString());
        cp_count = cp.size();
        dataoutputstream.writeShort(cp_count);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write CP Count is ").append(cp_count).toString());
        writeCP(dataoutputstream);
        if (Debug.isEnabled())
            System.out.println("Write CP Finished");
        dataoutputstream.writeShort(access);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write Access ").append(access).toString());
        dataoutputstream.writeShort(this_index);
        if (Debug.isEnabled()) {
            System.out.print((new StringBuilder()).append("Write this ").append(this_index).toString());
            CPClass cpclass = (CPClass) cp.getCPEntryAtIndex(this_index);
            CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(cpclass.getNameIndex());
            System.out.println((new StringBuilder()).append(" Class Name is ").append(cputf8.getString()).toString());
        }
        dataoutputstream.writeShort(super_index);
        if (Debug.isEnabled()) {
            System.out.print((new StringBuilder()).append("Write super ").append(super_index).toString());
            CPClass cpclass1 = (CPClass) cp.getCPEntryAtIndex(super_index);
            CPUtf8 cputf8_1 = (CPUtf8) cp.getCPEntryAtIndex(cpclass1.getNameIndex());
            System.out.println((new StringBuilder()).append(" Super Class Name is ").append(cputf8_1.getString()).toString());
        }
        int interface_count = interfaces.size();
        dataoutputstream.writeShort(interface_count);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write Interface ").append(interface_count).toString());
        if (interface_count != 0) {
            for (int i = 0; i < interface_count; i++) {
                CPClass c = interfaces.elementAt(i);
                dataoutputstream.writeShort(cp.indexOf(c));
            }

            if (Debug.isEnabled())
                System.out.println("Write Interface Finished");
        }
        dataoutputstream.writeShort(field_count);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Write Field  Count ").append(field_count).append("  Pleas Check This Code after").toString());
        writeField(dataoutputstream);
        method_count = mds.size();
        dataoutputstream.writeShort(method_count);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Method count ").append(method_count).toString());
        writeMethod(dataoutputstream);
        attribute_count = atts.size();
        dataoutputstream.writeShort(attribute_count);
        if (Debug.isEnabled())
            System.out.println((new StringBuilder()).append("Attribute Count ").append(attribute_count).toString());
        writeAttribute(dataoutputstream);
    }

    private void writeField(DataOutputStream dataoutputstream)
            throws IOException {
        if (field_count != 0) {
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("Write Field.size() ").append(fds.size()).toString());
            for (int i = 0; i < fds.size(); i++) {
                Field field = (Field) fds.elementAt(i);
                if (Debug.isEnabled()) {
                    System.out.print((new StringBuilder()).append("Field[").append(i).append("]:").toString());
                    CPUtf8 cputf8 = (CPUtf8) cp.getCPEntryAtIndex(field.getNameIndex());
                    System.out.print((new StringBuilder()).append(" Name:").append(cputf8.getString()).append(" Index:").append(field.getNameIndex()).toString());
                    cputf8 = (CPUtf8) cp.getCPEntryAtIndex(field.getSigIndex());
                    System.out.print((new StringBuilder()).append(" Sig:").append(cputf8.getString()).append(" Index:").append(field.getSigIndex()).toString());
                    System.out.println((new StringBuilder()).append(" Data:").append(field.getAccess()).append(" ").append(field.getNameIndex()).append(" ").append(field.getSigIndex()).append(" ").toString());
                }
                field.write(dataoutputstream);
            }

        }
    }

    private void writeMethod(DataOutputStream dataoutputstream)
            throws IOException {
        if (method_count != 0) {
            if (Debug.isEnabled())
                System.out.println((new StringBuilder()).append("Write Method.size() ").append(mds.size()).toString());
            for (int i = 0; i < mds.size(); i++) {
                Method method = (Method) mds.elementAt(i);
                method.write(dataoutputstream);
                if (Debug.isEnabled())
                    System.out.println((new StringBuilder()).append("Method ").append(i).toString());
            }

            if (Debug.isEnabled())
                System.out.println("Method is Finished");
        }
    }

    private void writeAttribute(DataOutputStream dataoutputstream)
            throws IOException {
        attribute_count = atts.size();
        if (attribute_count > 0) {
            for (int i = 0; i < atts.size(); i++) {
                if (Debug.isEnabled())
                    System.out.println((new StringBuilder()).append("Attribute ").append(i).toString());
                Object obj = atts.elementAt(i);
                Attribute attribute = (Attribute) obj;
                attribute.write(dataoutputstream);
            }

        }
    }
}